<?php

namespace 中文汇编器;
class 伪指令
{
	private $伪指令名 = ['无操作', '字节补码', '尾调用', '非0则置位', '小于0则置位', '是0则转至',
                        '非0则转至', '取局部地址', '调用', '返回', '取直接数', '小于0则转至', '大于0则转至',
                        '小于等于0则转至', '大于等于0则转至', '移动', '跳至直接数', '跳至寄存器'];
    private $寄存器名 = ['x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9', 'x10',
                        'x11', 'x12', 'x13', 'x14', 'x15', 'x16', 'x17', 'x18', 'x19', 'x20',
                        'x21', 'x22', 'x23', 'x24', 'x25', 'x26', 'x27', 'x28', 'x29', 'x30', 'x31',
                        'zero', 'ra', 'sp', 'gp', 'tp', 't0', 't1', 't2', 's0', 's1',
                        'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7',
                        's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's10', 's11',
                        't3', 't4', 't5', 't6', 'mvendorid', 'marchid', 'mimpid', 'mhartid', 'mstatus', 'misa', 'medeleg',
                        'mideleg', 'mie', 'mtvec', 'mcounteren', 'mstatush', 'mscratch', 'mepc', 'mcause', 'mtval', 'mip',
                         'minst', 'mtval2', 'pmpcfg0', 'pmpcfg1', 'pmpcfg2', 'pmpcfg3', 'pmpaddr0', 'pmpaddr1', 'pmpaddr2', 'pmpaddr3', 'pmpaddr4',
                         'pmpaddr5', 'pmpaddr6', 'pmpaddr7', 'pmpaddr8', 'pmpaddr9', 'pmpaddr10', 'pmpaddr11', 'pmpaddr12', 'pmpaddr13', 'pmpaddr14',
                         'pmpaddr15', 'mcycle', 'minstret', 'mcycleh', 'minstreth', 'cycle', 'time', 'instret', 'cycleh', 'timeh', 'instreth'];
	private $局部标签 = [];
	private $全局标签 = [];

	private $待翻译指令 = [];
	private $cl;

	public function __construct($lLabel, $gLabel)
	{
		$this->局部标签 = $lLabel;
		$this->全局标签 = $gLabel;
	}

	public function 置长度位($lb)
    {
        $this->cl = $lb;
    }

	public function 判断($opName)
	{
		$wzl = in_array($opName, $this->伪指令名);
		if ($wzl == true) 
			return true;
		else 
			return false;
	}

	public function 翻译($ins)
	{
		$this->待翻译指令 = $ins;
		$opItem = mb_split('，', $this->待翻译指令["内容"]);
		switch ($opItem[0])
		{
			case '无操作':
				return $this->无操作();
			case '补码':
				return $this->补码($opItem[2], $opItem[1]);
			case '非0则置位':
				return $this->非0则置位($opItem[2], $opItem[1]);
			case '小于0则置位':
				return $this->小于0则置位($opItem[2], $opItem[1]);
			case '大于0则置位':
				return $this->大于0则置位($opItem[2], $opItem[1]);
			case '是0则转至':
				return $this->是0则转至($opItem[2]);
			case '非0则转至':
				return $this->非0则转至($opItem[2]);
            case '调用':
                return $this->调用($opItem[1]);
            case '返回':
                return $this->返回();
			case '尾调用':
				return $this->尾调用($opItem[1]);
            case '取局部地址':
                return $this->取局部地址($opItem[3], $opItem[1]);
            case '取直接数':
                return $this->取直接数($opItem[3], $opItem[1]);
            case '小于等于0则转至':
                return $this->小于等于0则转至($opItem[3], $opItem[1]);
            case '大于等于0则转至':
                return $this->大于等于0则转至($opItem[3], $opItem[1]);
            case '小于0则转至':
                return $this->小于0则转至($opItem[3], $opItem[1]);
            case '大于0则转至':
                return $this->大于0则转至($opItem[3], $opItem[1]);
            case '跳至直接数':
                return $this->跳至直接数($opItem[1]);
            case '跳至寄存器':
                return $this->跳至寄存器($opItem[1]);
            case '移动':
                return $this->移动($opItem[1], $opItem[3]);
		}
	}

	private function 标签替换($label)
    {
        if ($this->cl == 1)
        {
            //var_dump($label);
            return($label);
        }

        $this->cl = 0;
        $n = count($this->全局标签);
        for ($j = 0; $j < $n; $j++)
        {
            if ($this->全局标签[$j]["标签名"] == $label)
                return ($label);
        }

        $n = count($this->局部标签);
        for ($j = 0; $j < $n; $j++)
        {
            if ($this->局部标签[$j]["标签名"] == ('_' . $this->待翻译指令["文件序号"] . '_' . $label))
                return ('_' . $this->待翻译指令["文件序号"] . '_' . $label);
        }

        if (is_numeric($label) == true)
        {
            $num = intval($label, 0);
            return($num);
        }

        $chr2 = mb_substr($label, 0, 2);
        if ($chr2 == '0x' or $chr2 == '0b')
        {
            $chrOther2 = mb_substr($label, 2);
            if (is_numeric($chrOther2) == false)
                exit('错误：' . $this->待翻译指令["文件名"] . '的第【' . $this->待翻译指令["行数"] . '】行，【' . $label . '】标签未定义');
            $num = intval($label, 0);
            return($num);
        }

		$chr1 = mb_substr($label, 0, 1);
		if ($chr1 == '0')
        {
            $chrOther1 = mb_substr($label, 1);
            if (is_numeric($chrOther1) == false)
                exit('错误：' . $this->待翻译指令["文件名"] . '的第【' . $this->待翻译指令["行数"] .  '】行，【' . $label . '】标签未定义');
            $num = intval($label, 0);
            return($num);
        }

        exit('错误：' . $this->待翻译指令["文件名"] . '的第【' . $this->待翻译指令["行数"] .  '】行，【' . $label . '】标签未定义');

	}

	private function 合法寄存器名($regs)
	{
		foreach ($regs as $reg)
		{
			if (in_array($reg, $this->寄存器名)) 
				return(true);
			else
				exit('错误：' . $this->待翻译指令["文件名"] . '的第【' . $this->待翻译指令["行数"] .  '】行，【' . $reg . '】错误的寄存器名称');
		}
	}

	private function 无操作()
	{
		return('加直接数，x0，0，存于，x0');
	}

	private function 补码($rs, $rd)
	{
        $regs = [$rs, $rd];
        $this->合法寄存器名($regs);
		return('减，' . $rs . '，x0，存于，' . $rd);
	}

	private function 非0则置位($rs, $rd)
	{
        $regs = [$rs, $rd];
        $this->合法寄存器名($regs);
		return('无符号小于则置位，' . $rd . '，比较，x0，' . $rs);
	}

	private function 小于0则置位($rs, $rd)
	{
        $regs = [$rs, $rd];
        $this->合法寄存器名($regs);
		return('小于则置位，' . $rd . '，比较，' . $rs . '，x0');
	}

	private function 大于0则置位($rs, $rd)
	{
        $regs = [$rs, $rd];
        $this->合法寄存器名($regs);
		return('小于则置位，' . $rd . '，比较，x0，' . $rs);
	}

	private function 是0则转至($rs, $offset)
	{
        $regs = [$rs];
        $this->合法寄存器名($regs);
		$str = $this->标签替换($offset);
		return('相等则转至，' . $str . '，比较，' . $rs . '，x0');
	}

	private function 非0则转至($rs, $offset)
	{
        $regs = [$rs];
        $this->合法寄存器名($regs);
		$str = $this->标签替换($offset);
		return('不等则转至，' . $str . '，比较，' . $rs . '，x0');
	}

	private function 小于等于0则转至($rs, $offset)
    {
        $regs = [$rs];
        $this->合法寄存器名($regs);
        $str = $this->标签替换($offset);
        return('大于等于则转至，' . $str . '，比较，x0，' . $rs);
    }

    private function 大于等于0则转至($rs, $offset)
    {
        $regs = [$rs];
        $this->合法寄存器名($regs);
        $str = $this->标签替换($offset);
        return('大于等于则转至，' . $str . '，比较，' . $rs . '，x0');
    }

    private function 小于0则转至($rs, $offset)
    {
        $regs = [$rs];
        $this->合法寄存器名($regs);
        $str = $this->标签替换($offset);
        return('小于则转至，' . $str . '，比较，' . $rs . '，x0');
    }

    private function 大于0则转至($rs, $offset)
    {
        $regs = [$rs];
        $this->合法寄存器名($regs);
        $str = $this->标签替换($offset);
        return('小于则转至，' . $str . '，比较，x0，' . $rs);
    }

	private function 尾调用($offset)
	{
		$lStr = $this->标签替换($offset);
		$str[] = 'PC加直接数高位，' . $lStr . '，存于，x6';
		$str[] = '寄存器跳转至，x6，' . $lStr . '，回调于，x0';
		//var_dump($str);
		return($str);
	}

	private function 跳至直接数($offset)
    {
        $str = $this->标签替换($offset);
        return('直接数跳转至，' . $str . '，回调于，x0');
    }

    private function 跳至寄存器($rs)
    {
        $regs = [$rs];
        $this->合法寄存器名($regs);
        return('寄存器跳转至，' . $rs . '，0，回调于，x0');
    }

    private function 返回()
    {
        return('寄存器跳转至，x1，0，回调于，x0');
    }

	private function 取局部地址($rd, $symbol)
    {
        $regs = [$rd];
        $this->合法寄存器名($regs);
        $lStr = $this->标签替换($symbol);
        $str[] = 'PC加直接数高位，' . $lStr . '，存于，' . $rd;
        $str[] = '加直接数，' . $rd . '，' . $lStr . '，存于，' . $rd;
        //var_dump($str);
        return($str);
    }

    private function 调用($offset)
    {
        $lStr = $this->标签替换($offset);
        $str[] = 'PC加直接数高位，' . $lStr . '，存于，x1';
        $str[] = '寄存器跳转至，x1， ' . $lStr . '，回调于，x1';
        //var_dump($str);
        return($str);
    }

    private function 取直接数($rd, $imm)
    {
        $regs = [$rd];
        $this->合法寄存器名($regs);
        $lStr = $this->标签替换($imm);
        $str[] = '取直接数高位，' . $lStr . '，存于，' . $rd;
        $str[] = '加直接数，' . $rd . '，' . $lStr . '，存于，' . $rd;
        return($str);
    }

    private function 移动($rs, $rd)
    {
        $regs = [$rs, rd];
        $this->合法寄存器名($regs);
        return('加，' . $rs . '，x0，存于，' . $rd);
    }

}
